#include "Movement.h"

#include "../CommandManager.h"
#include "../GameObjects/Room.h"
#include "../GameObjects/Character.h"
#include "../Player.h"
#include "../Random.h"
#include "../Time.h"
#include "../Input.h"

#include <iostream>

void Movement::Init()
{
	CommandManager::getSingleton()->add(std::make_shared<MoveWest>());
	CommandManager::getSingleton()->add(std::make_shared<MoveNorth>());
	CommandManager::getSingleton()->add(std::make_shared<MoveEast>());
	CommandManager::getSingleton()->add(std::make_shared<MoveSouth>());
	CommandManager::getSingleton()->add(std::make_shared<MoveUp>());
	CommandManager::getSingleton()->add(std::make_shared<MoveDown>());
}

void Movement::DoMove(const CharacterPtr &character, const RoomPtr &room, Exit::ExitId direction)
{
	const ExitPtr &exit = room->getExit(direction);
	if(exit)
	{
		if(exit->isLocked())
		{
			if(character->hasPlayer())
				std::cout << "That direction is blocked!" << std::endl;
		}
		else
		{
			if(exit->has(Exit::SLIPPERY_DOWN))
			{
				std::cout << "You slide down the " << exit->getTo()->getName() << ", barely standing on your feet." << std::endl;
                Input::getSingleton()->block_input();
				Time::wait(1000);
                Input::getSingleton()->unblock_input();
			}
			else if(exit->has(Exit::SLIPPERY_UP))
			{
				//There's a small chance to get to the top. This could also be determined by skill later...
				auto random = Random::getSingleton();
				random->randomize();
				if(random->rand(100) > 90) 
				{
					std::cout << "You strive and you claw up the " << room->getName() << ". With a lot of effort you make your way to the top." << std::endl;
					Input::getSingleton()->block_input();
				    Time::wait(1000);
                    Input::getSingleton()->unblock_input();
				}
				else
				{
					std::cout << "You strive and you claw up the " << room->getName() << ", but to no avail. You slide back down." << std::endl;
                    Input::getSingleton()->block_input();
				    Time::wait(1000);
                    Input::getSingleton()->unblock_input();
					return;
				}
			}

			room->exit(character, direction);
			exit->getTo()->enter(character, Exit::getOpposite(direction));
			if(character->hasPlayer())
				character->getPlayer()->setRoom(exit->getTo());
		}
	}
	else if(character->hasPlayer())
	{
		std::cout << "You can't walk in that direction." << std::endl;
	}
}

///////////////////////////////////////
// MOVE WEST
///////////////////////////////////////
MoveWest::MoveWest() : Command("west")
{
	add("w");
}
void MoveWest::execute(const CharacterPtr &character, const RoomPtr &room, const std::vector<std::string> &/*args*/)
{
	Movement::DoMove(character, room, Exit::WEST);
}

///////////////////////////////////////
// MOVE NORTH
///////////////////////////////////////
MoveNorth::MoveNorth() : Command("north")
{
	add("n");
}
void MoveNorth::execute(const CharacterPtr &character, const RoomPtr &room, const std::vector<std::string> &/*args*/)
{
	Movement::DoMove(character, room, Exit::NORTH);
}

///////////////////////////////////////
// MOVE EAST
///////////////////////////////////////
MoveEast::MoveEast() : Command("east")
{
	add("e");
}
void MoveEast::execute(const CharacterPtr &character, const RoomPtr &room, const std::vector<std::string> &/*args*/)
{
	Movement::DoMove(character, room, Exit::EAST);
}

///////////////////////////////////////
// MOVE SOUTH
///////////////////////////////////////
MoveSouth::MoveSouth() : Command("south")
{
	add("s");
}
void MoveSouth::execute(const CharacterPtr &character, const RoomPtr &room, const std::vector<std::string> &/*args*/)
{
	Movement::DoMove(character, room, Exit::SOUTH);
}

///////////////////////////////////////
// MOVE UP
///////////////////////////////////////
MoveUp::MoveUp() : Command("up")
{
	add("u");
}
void MoveUp::execute(const CharacterPtr &character, const RoomPtr &room, const std::vector<std::string> &/*args*/)
{
	Movement::DoMove(character, room, Exit::UP);
}

///////////////////////////////////////
// MOVE DOWN
///////////////////////////////////////
MoveDown::MoveDown() : Command("down")
{
	add("d");
}
void MoveDown::execute(const CharacterPtr &character, const RoomPtr &room, const std::vector<std::string> &/*args*/)
{
	Movement::DoMove(character, room, Exit::DOWN);
}
